#include<ysip2.h>



using namespace std;
vector<YSIP2_IP_INFO> gIpInfo;
vector<YSIP2_REGION_INFO> gRegionInfo;
#ifdef YSIP2_IP_DATA_ALL
vector<string> gDetailInfo;
#endif


template <class T>
bool ysipLoadData(const string file, vector<T> & vec) {
	int i = 0; 
	char buffer[1024];
	int count = 0;
	if(vec.size()  < 1) {
		ifstream infile;
		infile.open(file.c_str(), ifstream::in);
		if(infile.is_open()) {
			count = 0;
			while(infile.good()) {
				infile.getline(buffer, 1024);
				count++;
			}
			infile.clear(ifstream::goodbit);
			infile.seekg(0, ifstream::beg);

			i = 0;
			vec.resize(count);
			while(infile.good() && i < count) {
				infile.getline(buffer, 1024);
				vec[i] = buffer;
				i++;
			}
			infile.close();
		} else {
			cerr << "YSIP2: Open " << file << " error !" << endl;
			return false;
		}
	}	
	return true;
}

bool ysipInit(const string root) {
	bool ret = false;
	ret = ysipLoadData(root + "/region.txt", gRegionInfo) && ysipLoadData(root + "/ip.txt", gIpInfo);
#if defined(YSIP2_IP_DATA_ALL)
	if(ret) {
		ret &= ysipLoadData(root + "/detail.txt", gDetailInfo);	
	}	
#endif
	return ret;

}
bool ysipGetIpInfo(const string ip, YSIP2_REGION_INFO & regionInfo){
	unsigned int uip = htonl(inet_addr(ip.c_str()));		
	vector<YSIP2_IP_INFO>::iterator iter = lower_bound(gIpInfo.begin(),gIpInfo.end(), uip);
	if( iter != gIpInfo.end() && (*iter == uip)) {
		if(ysipGetRegionInfo(iter->region_id, regionInfo)) {
			return true;
		}
	}
	return false;
}

#ifdef YSIP2_IP_DATA_ALL
bool ysipGetIpInfo(const string ip, YSIP2_REGION_INFO_EX & regionInfo) {
	unsigned int uip = htonl(inet_addr(ip.c_str()));		
	vector<YSIP2_IP_INFO>::iterator iter = lower_bound(gIpInfo.begin(),gIpInfo.end(), uip);
	if( iter != gIpInfo.end() && (*iter == uip)) {
		if(ysipGetRegionInfo(iter->region_id, regionInfo)) {
			regionInfo.detail = gDetailInfo[iter->position];
			return true;
		}
	}
	return false;
}
#endif

bool ysipGetRegionInfo(const int id, YSIP2_REGION_INFO &regionInfo) {
	vector<YSIP2_REGION_INFO>::iterator iter = lower_bound(gRegionInfo.begin(), gRegionInfo.end(), id);
	if(iter != gRegionInfo.end() && (*iter == id)) {
		regionInfo = *iter;	
		return true;
	}
	return false;
}

bool ysipGetRegionChilds(const int id, vector<YSIP2_REGION_INFO> &childs, bool includeSelf){
	vector<YSIP2_REGION_INFO>::iterator iter;
	YSIP2_REGION_INFO regionInfo;
	// 100000 's level is 0, if level is 0 , we will not optimizer.
	// other's we will only walk through the xx0000 due to the data is so, just a trick.
#ifdef YSIP2_X_FORMAT
	if(id > 100000) {
		iter = lower_bound(gRegionInfo.begin(), gRegionInfo.end(), id);
		// if can found.
		if(iter != gRegionInfo.end() && (*iter == id)) {
			// if include self.
			if(includeSelf) {
				childs.push_back(*iter);
			}	

			for(iter++; iter != gRegionInfo.end(); iter++) {
				if(iter->id / 10000 != childs[0].id / 10000) {
					break;
				}
				if(iter->parent_id == id) {
					childs.push_back(*iter);
				}
			}
			return true;
		}
	} else if(id == 100000) {
		static vector<YSIP2_REGION_INFO> china;
		if(china.size() < 1) {
			for(iter = gRegionInfo.begin(); iter != gRegionInfo.end(); iter ++) {
				if(iter->parent_id == id) {
					china.push_back(*iter);
				}
			}
		}
		childs = china;
		if(includeSelf) {
			childs.insert(childs.begin(), gRegionInfo[0]);
		}
		return true;
	}
#else

	if(ysipGetRegionInfo(id, regionInfo)) {
		if(includeSelf) {
			childs.push_back(regionInfo);
		}
		for(iter = gRegionInfo.begin(); iter < gRegionInfo.end(); iter++) {
			if(iter->parent_id == id) {
				childs.push_back(*iter);
			}
		}
		return true;
	}
#endif
	return false;
}

bool ysipGetRegionParent(const int id, YSIP2_REGION_INFO & regionInfo) {
	if(ysipGetRegionInfo(id, regionInfo)) {
		if(regionInfo.parent_id != 0) {
			regionInfo = gRegionInfo[regionInfo.parent_pos];
			return true;
		}
	}
	return false;
}

bool ysipGetRegionParents(const int id, vector<YSIP2_REGION_INFO> & parents, bool includeSelf) {
	vector<YSIP2_REGION_INFO>::iterator iter;
	YSIP2_REGION_INFO regionInfo;
	if(ysipGetRegionInfo(id, regionInfo)) {
		if(includeSelf) {
			parents.push_back(regionInfo);	
		}
		while(regionInfo.parent_id != 0) {
			parents.push_back(gRegionInfo[regionInfo.parent_pos]);
			regionInfo = & gRegionInfo[regionInfo.parent_pos];
		}
		return true;
	}
	return false;
}

int ysipGetStat(int type) {
	if(type == 1) {
		return gRegionInfo.size();
	} else if(type == 2) {
		return gIpInfo.size();
	}
	return  gDetailInfo.size();
}

